/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package managedbean.MrpMps;

import merlion.mrp.ppm.pojo.LongHolder;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import javax.ejb.EJB;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import managedbean.Workspace.WorkspaceManagerBean;
import merlion.common.util.Consts;
import merlion.mrp.ppm.entity.DailyMPS;
import merlion.mrp.ppm.entity.DailyPlannedProduction;
import merlion.mrp.ppm.entity.Product;
import merlion.mrp.ppm.pojo.ScheduleResultTemp;
import merlion.mrp.ppm.session.MPSPlanningSessionLocal;

/**
 *
 * @author Zhang Ying
 */
@ManagedBean
@ViewScoped
public class DailyMpsManagerBean {

    public static final String NEW_DMPS = "NEWDMPS";
    @EJB
    private MPSPlanningSessionLocal mspSession;
    @ManagedProperty(value = "#{workspaceManagerBean}")
    private WorkspaceManagerBean workspaceManagerBean;
    // for seleciton list
    private Integer selectedYear;
    private String selectedMonth;
    private Integer selectedWeek;
    private List<Integer> yearList;
    private List<String> monthList;
    private List<Integer> weekList;
    private ArrayList<Integer> counterForProduct;
    private ArrayList<Integer> counterForWeek;
    // for detail page
    private DailyMPS newDMPS;
    private ArrayList<ArrayList<Long>> dailyDemands;
    private ArrayList<ArrayList<LongHolder>> dailyDemandsInput;
    private ArrayList<ArrayList<Long>> dailyOTDemands;
    private ArrayList<ArrayList<LongHolder>> dailyOTDemandsInput;
    private ArrayList<Timestamp> times;
    private ArrayList<Long> monthlyDemands;
    private Integer totalWorkingDays;
    // for scheduling dialog
    private ScheduleResultTemp scheduleResult;

    /** Creates a new instance of DailyMpsManagerBean */
    public DailyMpsManagerBean() {
        counterForProduct = new ArrayList<Integer>();
        for (int i = 0; i < 4; i++) {
            counterForProduct.add(i);
        }
        counterForWeek = new ArrayList<Integer>();
        for (int i = 0; i < 5; i++) {
            counterForWeek.add(i);
        }
        scheduleResult = new ScheduleResultTemp();
    }

    // for select page
    public String redirectToCreateDailyMPSDetail() {
        if (!mspSession.checkAbleToCreateDailyMPS(selectedYear, getMonthIndex(selectedMonth), selectedWeek)) {
            FacesContext.getCurrentInstance().addMessage(null,
                    new FacesMessage(FacesMessage.SEVERITY_ERROR, "Unsuccessful",
                    "Sorry, you are not allowed to create daily mps for this period yet. Please select another period."));
            return null;
        }
        Calendar calendar = Calendar.getInstance();
        Date date = calendar.getTime();
        DailyMPS nDMPS = new DailyMPS(selectedYear, getMonthIndex(selectedMonth), selectedWeek, new Timestamp(date.getTime()));

        FacesContext.getCurrentInstance().getExternalContext().getSessionMap().remove(NEW_DMPS);
        FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put(NEW_DMPS, nDMPS);

        return getRedirectPath(Consts.CREATE_DAILY_MPS_PATH + "Detail");
    }

    public List<String> getMonthList() {
        if (monthList == null) {
            monthList = new ArrayList<String>();
            for (int i = 1; i <= 12; i++) {
                monthList.add(getMonthEnglish(i));
            }
        }
        return monthList;
    }

    public void setMonthList(List<String> monthList) {
        this.monthList = monthList;
    }

    public MPSPlanningSessionLocal getMspSession() {
        return mspSession;
    }

    public void setMspSession(MPSPlanningSessionLocal mspSession) {
        this.mspSession = mspSession;
    }

    public String getSelectedMonth() {
        return selectedMonth;
    }

    public void setSelectedMonth(String selectedMonth) {
        this.selectedMonth = selectedMonth;
    }

    public Integer getSelectedWeek() {
        return selectedWeek;
    }

    public void setSelectedWeek(Integer selectedWeek) {
        this.selectedWeek = selectedWeek;
    }

    public Integer getSelectedYear() {
        return selectedYear;
    }

    public void setSelectedYear(Integer selectedYear) {
        this.selectedYear = selectedYear;
    }

    public List<Integer> getWeekList() {
        if (weekList == null) {
            weekList = new ArrayList<Integer>();
            for (int i = 1; i < 6; i++) {
                weekList.add(i);
            }
        }
        return weekList;
    }

    public void setWeekList(List<Integer> weekList) {
        this.weekList = weekList;
    }

    public List<Integer> getYearList() {
        if (yearList == null) {
            Calendar calendar = Calendar.getInstance();
            Date date = calendar.getTime();
            int currentYear = Integer.valueOf(Consts.sdfYear.format(date));
            yearList = new ArrayList<Integer>();
            for (int i = currentYear; i < (currentYear + 5); i++) {
                yearList.add(i);
            }
        }
        return yearList;
    }

    public void setYearList(List<Integer> yearList) {
        this.yearList = yearList;
    }

    // for detail page
    public String calculateDMPS() {
        //  add validations
        // 1. check 90%
        for (int j = 0; j < 5; j++) {
            Integer totalDaysPW = 16;
            double sumOfHrs = Long.valueOf(0);
            Integer totalDaysPWP = 8;
            double sumOfHrsP = Long.valueOf(0);
            for (int i = 0; i < 4; i++) {
                if (i == 0 || i == 1) {
                    sumOfHrs += 1.0 * dailyDemands.get(i).get(j) / Consts.CASES_PER_HOUR_CLASSIC;
                    sumOfHrsP += 1.0 * dailyOTDemands.get(i).get(j) / Consts.CASES_PER_HOUR_CLASSIC;
                } else {
                    sumOfHrs += 1.0 * dailyDemands.get(i).get(j) / Consts.CASES_PER_HOUR_PREMIUM;
                    sumOfHrsP += 1.0 * dailyOTDemands.get(i).get(j) / Consts.CASES_PER_HOUR_PREMIUM;
                }
            }
            if (totalDaysPW != 0 && 1.0 * sumOfHrs / totalDaysPW > 0.9) {
                FacesContext.getCurrentInstance().addMessage(null,
                        new FacesMessage(FacesMessage.SEVERITY_ERROR, "Unsuccessful",
                        "Please make sure the utilization for normal shift is less than 90%."));
                return null;
            }
            if (totalDaysPWP != 0 && 1.0 * sumOfHrsP / totalDaysPWP > 0.9) {
                FacesContext.getCurrentInstance().addMessage(null,
                        new FacesMessage(FacesMessage.SEVERITY_ERROR, "Unsuccessful",
                        "Please make sure the utilization for overtime shift is less than 90%."));
                return null;
            }
        }
        // 2. check whether 21 days
        Calendar c1 = Calendar.getInstance();
        Calendar c2 = Calendar.getInstance();
        c1.set(newDMPS.getStartPeriodYear(), newDMPS.getStartPeriodMonth() -1, newDMPS.getStartPeriodDate(),0,0,0);
        // for testing
//        c2.set(2011, 12, 24);
        long millis1 = c1.getTimeInMillis();
        long millis2 = c2.getTimeInMillis(); // current time

        long d = (millis1 - millis2) / (24 * 60 * 60 * 1000);

        if (d <= 21) {
            // check for raw material
            if (!mspSession.checkRawMaterial(newDMPS)){
                FacesContext.getCurrentInstance().addMessage(null,
                        new FacesMessage(FacesMessage.SEVERITY_ERROR, "Unsuccessful",
                        "Sorry. You don't have enough material. Please edit your inputs"));
                return null;
            }
        }
        // set the holders' values to newDMPS
        for (int i = 0; i < 4; i++) {
            for (int j = 0; j < 5; j++) {
                DailyPlannedProduction dpp = newDMPS.returnIndivDMPS(i).returnDailyPlannedProduction(j);
                dpp.setDailyDemand(dailyDemandsInput.get(i).get(j).getL());
                dpp.setDailyOTDemand(dailyOTDemandsInput.get(i).get(j).getL());
            }
        }
        //debugging
//        for (int i = 0; i < 4; i++) {
//            for (int j = 0; j < 5; j++) {
//                DailyPlannedProduction dpp = newDMPS.returnIndivDMPS(i).returnDailyPlannedProduction(j);
//                System.out.println("dpp " + dpp.getDailyDemand() + " " + dpp.getDailyOTDemand());
//            }
//        }
        return null;
    }

    public void scheduleDMPS(ActionEvent event) {
        // call schedule function
        scheduleResult = mspSession.getScheduleResult(newDMPS);
    }

    public ScheduleResultTemp getScheduleResult() {
        return scheduleResult;
    }

//    public String confirmDMPS() {
//        // debugging
////        for (int i = 0; i < 4; i++) {
////            for (int j = 0; j < 5; j++) {
////                DailyPlannedProduction dpp = newDMPS.returnIndivDMPS(i).returnDailyPlannedProduction(j);
////                System.out.println("dpp " + dpp.getDailyDemand() + " " + dpp.getDailyOTDemand());
////            }
////        }
//        // persist
//        if (mspSession.persistDailyMPS(newDMPS, workspaceManagerBean.getCurrentStaff().getId())) {
//            FacesContext.getCurrentInstance().getExternalContext().getSessionMap().remove(NEW_DMPS);
//            return getRedirectPath(Consts.CREATE_DAILY_MPS_PATH + "Confirm");
//        } else {
//            FacesContext.getCurrentInstance().addMessage(null,
//                    new FacesMessage(FacesMessage.SEVERITY_ERROR, "Unsuccessful",
//                    "not able to persist into the database"));
//            return null;
//        }
//    }

    public String resetDMPS() {
        dailyDemandsInput = new ArrayList<ArrayList<LongHolder>>();
        dailyOTDemandsInput = new ArrayList<ArrayList<LongHolder>>();
        for (int i = 0; i < 4; i++) {
            ArrayList<LongHolder> ddi = new ArrayList<LongHolder>();
            ArrayList<LongHolder> dotdi = new ArrayList<LongHolder>();
            for (int j = 0; j < 5; j++) {
                DailyPlannedProduction dpp = newDMPS.returnIndivDMPS(i).returnDailyPlannedProduction(j);
                dpp.setDailyDemand(dailyDemands.get(i).get(j));
                dpp.setDailyOTDemand(dailyOTDemands.get(i).get(j));

                LongHolder temp1 = new LongHolder();
                temp1.setL(dailyDemands.get(i).get(j));
                LongHolder temp2 = new LongHolder();
                temp2.setL(dailyOTDemands.get(i).get(j));
                ddi.add(temp1);
                dotdi.add(temp2);
            }
            dailyDemandsInput.add(ddi);
            dailyOTDemandsInput.add(dotdi);
        }
        return null;
    }

    public DailyMPS getNewDMPS() {
        if (newDMPS == null) {
            DailyMPS temp = (DailyMPS) FacesContext.getCurrentInstance().getExternalContext().getSessionMap().get(NEW_DMPS);
            if (temp != null) {
                newDMPS = temp;
            }
        }
        return newDMPS;
    }

    public void setNewDMPS(DailyMPS newDMPS) {
        this.newDMPS = newDMPS;
    }

    public ArrayList<ArrayList<LongHolder>> getDailyDemandsInput() {
        fillInputs();
        return dailyDemandsInput;
    }

    public void setDailyDemandsInput(ArrayList<ArrayList<LongHolder>> dailyDemandsInput) {
        this.dailyDemandsInput = dailyDemandsInput;
    }
    
    public ArrayList<ArrayList<LongHolder>> getDailyOTDemandsInput() {
        fillInputs();
        return dailyOTDemandsInput;
    }
    
    private void fillInputs(){
        if (dailyDemandsInput == null || dailyDemandsInput.isEmpty()) {
            dailyDemandsInput = new ArrayList<ArrayList<LongHolder>>();
            dailyOTDemandsInput = new ArrayList<ArrayList<LongHolder>>();
            for (int i = 0; i < 4; i++) {
                ArrayList<LongHolder> ddi = new ArrayList<LongHolder>();
                ArrayList<LongHolder> dotdi = new ArrayList<LongHolder>();
                for (int j = 0; j < 5; j++) {
                    DailyPlannedProduction dpp = newDMPS.returnIndivDMPS(i).returnDailyPlannedProduction(j);
                    dpp.setDailyDemand(getDailyDemands().get(i).get(j));
                    dpp.setDailyOTDemand(getDailyOTDemands().get(i).get(j));
                    dpp.setProductionDay(times.get(j));
                    Product p = mspSession.getProduct(i);
                    dpp.setProduct(p);

                    LongHolder temp1 = new LongHolder();
                    temp1.setL(dailyDemands.get(i).get(j));
                    LongHolder temp2 = new LongHolder();
                    temp2.setL(dailyOTDemands.get(i).get(j));
                    ddi.add(temp1);
                    dotdi.add(temp2);
                }
                dailyDemandsInput.add(ddi);
                dailyOTDemandsInput.add(dotdi);
            }
        }
    }

    public void setDailyOTDemandsInput(ArrayList<ArrayList<LongHolder>> dailyOTDemandsInput) {
        this.dailyOTDemandsInput = dailyOTDemandsInput;
    }

    public Integer returnNormalShift() {
        return Consts.NORMAL_SHIFT_PER_DAY;
    }

    public Integer returnOvertimeShift() {
        return Consts.OVERTIME_EXTRA_SHIFT_PER_DAY;
    }

    public Double returnDailyDemandInHours(Long dailyDemand, int productCounter) {
        if (productCounter == 0) {
            return (1.0 * dailyDemand / Consts.CASES_PER_HOUR_CLASSIC);
        } else if (productCounter == 1) {
            return (1.0 * dailyDemand / Consts.CASES_PER_HOUR_CLASSIC);
        } else if (productCounter == 2) {
            return (1.0 * dailyDemand / Consts.CASES_PER_HOUR_PREMIUM);
        } else if (productCounter == 3) {
            return (1.0 * dailyDemand / Consts.CASES_PER_HOUR_PREMIUM);
        } else {
            return 0.0;
        }
    }

    public Double returnUtilizationNormalShift(Integer weekCount) {
        Integer totalDaysPW = 16;
        double sumOfHrs = Long.valueOf(0);
        for (int i = 0; i < 4; i++) {
            if (i == 0 || i == 1) {
                sumOfHrs += 1.0 * dailyDemands.get(i).get(weekCount) / Consts.CASES_PER_HOUR_CLASSIC;
            } else {
                sumOfHrs += 1.0 * dailyDemands.get(i).get(weekCount) / Consts.CASES_PER_HOUR_PREMIUM;
            }
        }
        if (totalDaysPW == 0) {
            return null;
        }
        return 1.0 * sumOfHrs / totalDaysPW;
    }

    public Double returnUtilizationOvertimeShift(Integer weekCount) {
        Integer totalDaysPW = 8;
        double sumOfHrs = Long.valueOf(0);
        for (int i = 0; i < 4; i++) {
            if (i == 0 || i == 1) {
                sumOfHrs += 1.0 * dailyOTDemands.get(i).get(weekCount) / Consts.CASES_PER_HOUR_CLASSIC;
            } else {
                sumOfHrs += 1.0 * dailyOTDemands.get(i).get(weekCount) / Consts.CASES_PER_HOUR_PREMIUM;
            }
        }
        if (totalDaysPW == 0) {
            return null;
        }
        return 1.0 * sumOfHrs / totalDaysPW;
    }

    public ArrayList<ArrayList<Long>> getDailyDemands() {
        if (dailyDemands == null) {
            dailyDemands = mspSession.getEachDayDemandForOneWeek(getNewDMPS().getStartPeriodYear(), getNewDMPS().getStartPeriodMonth(), getNewDMPS().getStartPeriodDate());
        }
        return dailyDemands;
    }

    public void setDailyDemands(ArrayList<ArrayList<Long>> dailyDemands) {
        this.dailyDemands = dailyDemands;
    }

    public ArrayList<Timestamp> getTimes() {
        if (times == null) {
            times = mspSession.getDatesforWeek(getNewDMPS().getStartPeriodYear(), newDMPS.getStartPeriodMonth(), newDMPS.getStartPeriodDate());
        }
        return times;
    }

    public void setTimes(ArrayList<Timestamp> times) {
        this.times = times;
    }

    public ArrayList<Long> getMonthlyDemands() {
        if (monthlyDemands == null) {
            monthlyDemands = mspSession.getMonthlyDemand(getNewDMPS().getStartPeriodMonth(), newDMPS.getStartPeriodYear());
        }
        return monthlyDemands;
    }

    public void setMonthlyDemands(ArrayList<Long> monthlyDemands) {
        this.monthlyDemands = monthlyDemands;
    }

    public Integer getTotalWorkingDays() {
        if (totalWorkingDays == null) {
            totalWorkingDays = mspSession.getTotalWorkingDaysForMonth(getNewDMPS().getStartPeriodMonth(), newDMPS.getStartPeriodYear());
        }
        return totalWorkingDays;
    }

    public void setTotalWorkingDays(Integer totalWorkingDays) {
        this.totalWorkingDays = totalWorkingDays;
    }

    public ArrayList<ArrayList<Long>> getDailyOTDemands() {
        if (dailyOTDemands == null){
            dailyOTDemands = new ArrayList<ArrayList<Long>>();
            for (int i = 0; i < 4; i ++){
                ArrayList<Long> temp = new ArrayList<Long>();
                for (int j = 0; j < 5; j++){
                    temp.add(0L);
                }
                dailyOTDemands.add(temp);
            }
        }
        return dailyOTDemands;
    }

    public void setDailyOTDemands(ArrayList<ArrayList<Long>> dailyOTDemands) {
        this.dailyOTDemands = dailyOTDemands;
    }

    // for general purpose
    public ArrayList<Integer> getCounterForProduct() {
        return counterForProduct;
    }

    public ArrayList<Integer> getCounterForWeek() {
        return counterForWeek;
    }

    private Long roundToLong(Double d) {
        return Math.round(d);
    }

    private String getRedirectPath(String path) {
        return path + "?faces-redirect=true";
    }

    private String getMonthEnglish(int i) {
        switch (i) {
            case 1:
                return Consts.JAN;
            case 2:
                return Consts.FEB;
            case 3:
                return Consts.MAR;
            case 4:
                return Consts.APR;
            case 5:
                return Consts.MAY;
            case 6:
                return Consts.JUN;
            case 7:
                return Consts.JUL;
            case 8:
                return Consts.AUG;
            case 9:
                return Consts.SEP;
            case 10:
                return Consts.OCT;
            case 11:
                return Consts.NOV;
            case 12:
                return Consts.DEC;
            default:
                return "";
        }
    }

    private int getMonthIndex(String label) {
        if (label.equals(Consts.JAN)) {
            return 1;
        } else if (label.equals(Consts.FEB)) {
            return 2;
        } else if (label.equals(Consts.MAR)) {
            return 3;
        } else if (label.equals(Consts.APR)) {
            return 4;
        } else if (label.equals(Consts.MAY)) {
            return 5;
        } else if (label.equals(Consts.JUN)) {
            return 6;
        } else if (label.equals(Consts.JUL)) {
            return 7;
        } else if (label.equals(Consts.AUG)) {
            return 8;
        } else if (label.equals(Consts.SEP)) {
            return 9;
        } else if (label.equals(Consts.OCT)) {
            return 10;
        } else if (label.equals(Consts.NOV)) {
            return 11;
        } else if (label.equals(Consts.DEC)) {
            return 12;
        } else {
            return 0;
        }
    }

    public String returnProductAlpha(Integer i) {
        if (i.intValue() == 0) {
            //return Consts.ProductType.BAR_A.getText();
            return "A";
        } else if (i.intValue() == 1) {
            //return Consts.ProductType.BAR_B.getText();
            return "B";
        } else if (i.intValue() == 2) {
            //return Consts.ProductType.BAR_C.getText();
            return "C";
        } else if (i.intValue() == 3) {
            //return Consts.ProductType.BAR_D.getText();
            return "D";
        } else {
            return "";
        }
    }

    public String returnProductName(Integer i) {
        if (i.intValue() == 0) {
            return Consts.ProductType.BAR_A.getText();
        } else if (i.intValue() == 1) {
            return Consts.ProductType.BAR_B.getText();
        } else if (i.intValue() == 2) {
            return Consts.ProductType.BAR_C.getText();
        } else if (i.intValue() == 3) {
            return Consts.ProductType.BAR_D.getText();
        } else {
            return "";
        }
    }

    public String returnFormattedDay(Timestamp t) {
        if (t == null) {
            return "";
        }
        SimpleDateFormat sdf = new SimpleDateFormat("dd/MM");
        return sdf.format(t);
    }

    public WorkspaceManagerBean getWorkspaceManagerBean() {
        return workspaceManagerBean;
    }

    public void setWorkspaceManagerBean(WorkspaceManagerBean workspaceManagerBean) {
        this.workspaceManagerBean = workspaceManagerBean;
    }
}
